package com.camundademo.rest.exception;

import com.camundademo.rest.dto.Results;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


/**
 * 只处理Controller抛出的异常
 */
@Slf4j
@ControllerAdvice
@ResponseBody // ResponseBody标记在类上 标识所有的方法都是返回到ResponseBody中  每个方法上的ResponseBody可以省略
public class RestExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Results handlerException(
            Exception e,
            HttpServletRequest request,
            HttpServletResponse response
                                   ) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        log.error("请求uri【{}】", request.getRequestURI());
        log.error(e.getMessage(), e);
        Results results = new Results();
        results.setCode(Results.RespEnum.ERROR.getCode());
        results.setMsg("Exception UNKNOWN_ERROR");
        results.setData(e.getMessage());
        return results;
    }


    @ExceptionHandler(value = RuntimeException.class)
    @ResponseBody
    public Results handlerRuntimeException(
            RuntimeException e,
            HttpServletRequest request,
            HttpServletResponse response
                                          ) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        log.error("请求uri【{}】", request.getRequestURI());
        log.error(e.getMessage(), e);
        Results results = new Results();

        results.setCode(Results.RespEnum.ERROR.getCode());
        results.setMsg("RuntimeException UNKNOWN_ERROR");
        results.setData(e.toString());
        return results;
    }


    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseBody
    public Results handleNoHandlerFoundException(
            NoHandlerFoundException e,
            HttpServletRequest request,
            HttpServletResponse response
                                                ) {
        response.setStatus(HttpStatus.NOT_FOUND.value());
        log.error("请求uri【{}】", request.getRequestURI());
        log.error(e.getMessage(), e);

        Results results = new Results();
        results.setCode("404NoHandler");
        results.setMsg("找不到接口");
        results.setData(e.toString());
        return results;
    }


    @ExceptionHandler(NoResourceFoundException.class)
    public Results handleNoResourceFoundException(
            NoResourceFoundException e,
            HttpServletRequest request,
            HttpServletResponse response
                                                 ) {
        response.setStatus(HttpStatus.BAD_REQUEST.value());
        log.error("请求uri【{}】", request.getRequestURI());
        log.error(e.getMessage(), e);

        Results results = new Results();
        results.setCode("404NoResource");
        results.setMsg("找不到资源");
        results.setData(e.toString());
        return results;
    }

    /**
     * spring参数校验    类属性参数校验的异常处理
     *
     * @param ex
     * @return
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Results handleValidationExceptions(
            MethodArgumentNotValidException ex,
            HttpServletRequest request
                                             ) {

        log.error("请求uri【{}】", request.getRequestURI());
        log.error(ex.getMessage(), ex);
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });

        Results results = new Results();
        results.setCode("400ArgumentNotValid");
        results.setMsg(errors.toString());
        results.setData(errors);
        return results;
    }

    /**
     * spring参数校验   简单参数校验
     *
     * @param e
     * @param request
     * @param response
     * @return
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = HandlerMethodValidationException.class)
    @ResponseBody
    public Results handlerRuntimeException(
            HandlerMethodValidationException e,
            HttpServletRequest request,
            HttpServletResponse response
                                          ) {
        log.error("请求uri【{}】", request.getRequestURI());
        log.error(e.getMessage(), e);

        Results results = new Results();

        Map<String, String> errors = new HashMap<>();

        e.getAllErrors().forEach((error) -> {

            String fieldName = Arrays.stream(error.getArguments()).findFirst().map(
                    o -> (DefaultMessageSourceResolvable) o).get().getDefaultMessage();
            //System.out.println(fieldName);
            //String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });


        results.setCode("400HandlerMethodValid");
        results.setMsg(errors.toString());
        results.setData(errors);
        return results;
    }

}